package service

import (
	"gin/common"
	Mysql "gin/database"
	"gin/model"
	"gin/queue"
	"gin/response"
	nlpDict "gin/tai/dict"
	"gin/validate"
	"github.com/spf13/viper"
	"strings"
)

func CreateDict(Data validate.AddDict) (resData model.Dict, err error) {
	resData.Name = Data.Name
	resData.Description = Data.Description
	err = model.Insert(&resData)
	return
}

func FindDict(Param *common.Filter) (resData model.Dict, err error) {
	err = model.Find(&resData, Param.Filter, []string{})
	return
}

// 查询多条词库
func SelectDict(Param *common.SelectQueryParam) (total int64, resData []model.Dict, err error) {

	rows := []model.Dict{}
	res := response.SelectResp{}

	res.Rows = &rows
	err = model.Select(&model.Dict{}, &res, Param.Filter.Filter, Param.Limit, Param.Offset, Param.Fields, Param.Order, []string{})
	total = res.Total
	resData = rows
	return
}

// 更新词库
func UpdateDict(Data validate.UpdateDict) (resData model.Dict, err error) {
	_, err = model.Update(&model.Dict{}, map[string]interface{}{
		"eq": map[string]interface{}{
			"condition": "id = ?",
			"val":       Data.Id,
		},
	}, map[string]interface{}{
		"name":        Data.Name,
		"description": Data.Description,
	})
	if err != nil {
		return resData, err
	}
	err = model.FindById(&resData, Data.Id, nil)
	return resData, err
}

// 删除词库
func DeleteDict(param *common.Filter) error {

	dicts := make([]model.Dict, 0)
	result := response.SelectResp{
		Total: 0,
		Rows:  &dicts,
	}
	err := model.Select(&model.Dict{}, &result, param.Filter, viper.GetInt("mysql.maxQueryNumber"), 0, "*", "", []string{})

	if err != nil || result.Total <= 0 {
		return err
	}
	db := Mysql.DB
	for _, row := range dicts {
		res := db.Delete(&row)
		if res.Error != nil {
			return res.Error
		}
	}
	return err
}

func PullDict(dict *validate.PullDict) error {
	var limit uint64
	var offset uint64
	var page uint64
	limit = 100
	page = 1
	for {
		offset = limit * (page - 1)

		res, err := nlpDict.Select(&limit, &offset)

		if err != nil {
			return err
		}
		if len(res.Response.Dicts) == 0 {
			break
		}
		queue.EnQueue(&queue.PullDictJob{DictList: res.Response.Dicts})

		if len(res.Response.Dicts) < int(limit) {
			break
		}
		page += 1

	}

	return nil
}

func DictAddByEntityCustomTags(v *validate.DictAddByEntityCustomTags) (resData []model.DictWord, err error) {

	pos := getPos(v.Type)
	var words []string
	wordsMap := make(map[string]string)
	switch v.Type {
	case "shot":
		rows := int64(0)
		for {
			total, res, err := SelectShot(&common.SelectQueryParam{
				Filter: common.Filter{
					Filter: map[string]interface{}{
						"-lk": map[string]interface{}{
							"condition": "custom_tag is not null and custom_tag != ?",
							"val":       "",
						},
					},
				},
				Fields: "custom_tag",
				Limit:  viper.GetInt("mysql.maxQueryNumber"),
				Offset: 0,
				Order:  "",
			})
			if err != nil {
				break
			}
			if total == 0 {
				break
			}
			rows += int64(len(res))
			for _, shot := range res {
				for _, word := range strings.Split(shot.CustomTag, ",") {
					wordsMap[word] = word
				}
			}
			if rows == total {
				break
			}
		}
		break
	case "light":
		rows := int64(0)
		for {
			total, res, err := SelectLight(&common.SelectQueryParam{
				Filter: common.Filter{
					Filter: map[string]interface{}{
						"-lk": map[string]interface{}{
							"condition": "custom_tag is not null and custom_tag != ?",
							"val":       "",
						},
					},
				},
				Fields: "custom_tag",
				Limit:  viper.GetInt("mysql.maxQueryNumber"),
				Offset: 0,
				Order:  "",
			})
			if err != nil {
				break
			}
			if total == 0 {
				break
			}
			rows += int64(len(res))
			for _, light := range res {
				for _, word := range strings.Split(light.CustomTag, ",") {
					wordsMap[word] = word
				}
			}
			if rows == total {
				break
			}
		}

		break
	case "action":
		rows := int64(0)
		for {
			total, res, err := SelectAction(&common.SelectQueryParam{
				Filter: common.Filter{
					Filter: map[string]interface{}{
						"-lk": map[string]interface{}{
							"condition": "custom_tag is not null and custom_tag != ?",
							"val":       "",
						},
					},
				},
				Fields: "custom_tag",
				Limit:  viper.GetInt("mysql.maxQueryNumber"),
				Offset: 0,
				Order:  "",
			})
			if err != nil {
				break
			}
			if total == 0 {
				break
			}
			rows += int64(len(res))
			for _, action := range res {
				for _, word := range strings.Split(action.CustomTag, ",") {
					wordsMap[word] = word
				}
			}
			if rows == total {
				break
			}
		}
		break
	case "scene":
		rows := int64(0)
		for {
			total, res, err := SelectScene(&common.SelectQueryParam{
				Filter: common.Filter{
					Filter: map[string]interface{}{
						"-lk": map[string]interface{}{
							"condition": "custom_tag is not null and custom_tag != ?",
							"val":       "",
						},
					},
				},
				Fields: "custom_tag",
				Limit:  viper.GetInt("mysql.maxQueryNumber"),
				Offset: 0,
				Order:  "",
			})
			if err != nil {
				break
			}
			if total == 0 {
				break
			}
			rows += int64(len(res))
			for _, action := range res {
				for _, word := range strings.Split(action.CustomTag, ",") {
					wordsMap[word] = word
				}
			}
			if rows == total {
				break
			}
		}
		break
	case "role":
		rows := int64(0)
		for {
			total, res, err := SelectRole(&common.SelectQueryParam{
				Filter: common.Filter{
					Filter: map[string]interface{}{
						"-lk": map[string]interface{}{
							"condition": "custom_tag is not null and custom_tag != ?",
							"val":       "",
						},
					},
				},
				Fields: "custom_tag",
				Limit:  viper.GetInt("mysql.maxQueryNumber"),
				Offset: 0,
				Order:  "",
			})
			if err != nil {
				break
			}
			if total == 0 {
				break
			}
			rows += int64(len(res))
			for _, role := range res {
				for _, word := range strings.Split(role.CustomTag, ",") {
					wordsMap[word] = word
				}
			}
			if rows == total {
				break
			}
		}
	}

	if len(wordsMap) == 0 {
		return resData, nil
	}

	words = make([]string, len(wordsMap))
	index := 0
	for _, word := range wordsMap {
		words[index] = word
		index += 1
	}

	index = 0
	step := 100
	lengthOfWords := len(words)
	for {
		if index == lengthOfWords {
			break
		}
		end := index + step

		if end >= lengthOfWords {
			end = lengthOfWords
		}

		wordsTemp := words[index:end]

		var dictWords []model.DictWord
		Mysql.DB.Model(&model.DictWord{}).Where("dict_id = ?", v.DictId).Where("word in (?)", wordsTemp).Find(&dictWords)
		batchAdd := validate.BatchAddDictWord{
			DictId:     v.DictId,
			Pos:        pos,
			ExtendCode: v.Type,
		}
		if len(dictWords) == 0 {
			batchAdd.Words = wordsTemp
		} else {
			for _, word := range wordsTemp {
				inFlag := false
				for _, dictWord := range dictWords {
					if dictWord.Word == word {
						inFlag = true
					}
				}
				if inFlag == false {
					batchAdd.Words = append(batchAdd.Words, word)
				}
			}
		}
		if len(batchAdd.Words) > 0 {
			res, err := BatchCreateDictWord(batchAdd)
			if err != nil {
				return resData, err
			}
			resData = append(resData, res...)
		}

		index = end

	}

	return resData, err
}

// pos类型获得
func getPos(tableType string) (res string) {

	switch tableType {
	case "action":
		res = "v"
		break
	case "shot":
		res = "n"
		break
	case "light":
		res = "n"
		break
	case "role":
		res = "nr"
		break
	case "scene":
		res = "ns"
		break
	default:
		res = "n"
	}
	return res

}
